package jDemolitionMan;

/*
 * Copyright (c) 2005-2007 jME Physics 2
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 *  * Neither the name of 'jME Physics 2' nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

import handlers.ManejadorDeTeclas;

import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.jme.bounding.BoundingBox;
import com.jme.bounding.BoundingCapsule;
import com.jme.image.Texture;
import com.jme.image.Texture.MagnificationFilter;
import com.jme.image.Texture.MinificationFilter;
import com.jme.image.Texture.WrapMode;
import com.jme.input.ChaseCamera;
import com.jme.input.InputHandler;
import com.jme.input.KeyInput;
import com.jme.input.action.InputAction;
import com.jme.input.action.InputActionEvent;
import com.jme.input.thirdperson.ThirdPersonMouseLook;
import com.jme.math.FastMath;
import com.jme.math.LineSegment;
import com.jme.math.Quaternion;
import com.jme.math.Vector3f;
import com.jme.scene.Controller;
import com.jme.scene.Node;
import com.jme.scene.Spatial;
import com.jme.scene.shape.Box;
import com.jme.scene.state.TextureState;
import com.jme.util.TextureManager;
import com.jme.util.export.binary.BinaryImporter;
import com.jmex.physics.DynamicPhysicsNode;
import com.jmex.physics.StaticPhysicsNode;
import com.jmex.physics.contact.ContactInfo;
import com.jmex.physics.material.Material;
import com.jmex.physics.util.SimplePhysicsGame;
import com.model.md5.MD5Animation;
import com.model.md5.MD5Node;
import com.model.md5.controller.MD5Controller;
import com.model.md5.importer.MD5Importer;
import com.model.md5.interfaces.IMD5Animation;
import com.model.md5.interfaces.IMD5Controller;
import com.model.md5.interfaces.IMD5Node;

public class JDM extends SimplePhysicsGame {

	public static void main(String[] args) {
		Logger.getLogger("").setLevel(Level.WARNING); // to see the important
														// stuff
		JDM app = new JDM();
		app.setConfigShowMode(ConfigShowMode.ShowIfNoConfig);
		app.start();
	}

	private int alto = 20;
	private int ancho = 20;
	private ChaseCamera chaseCamera;

	StaticPhysicsNode floor;
	private boolean[][] mazeData;

	DynamicPhysicsNode player;

	private float tileSize = 10;
	
	
	private IMD5Node body;
	private MD5Importer importer;
	
	private MD5Controller bodyController;
	private HashMap<String, Object> props;
	

	

	private void buildChaseCamera() {

		props = new HashMap<String, Object>();
		props.put(ChaseCamera.PROP_INITIALSPHERECOORDS, new Vector3f(10, 10,
				60 * FastMath.DEG_TO_RAD));
		props.put(ChaseCamera.PROP_DAMPINGK, "4");
		props.put(ChaseCamera.PROP_SPRINGK, "9");
		props.put(ThirdPersonMouseLook.PROP_ENABLED, "false");
		chaseCamera = new ChaseCamera(cam, player, props);
		chaseCamera.setMaxDistance(60);
		chaseCamera.setMinDistance(50);
	}

	private void buildFloor() {
		StaticPhysicsNode floor;
		floor = getPhysicsSpace().createStaticNode();
		Spatial floorVisual = new Box("floor", new Vector3f(), tileSize * ancho
				/ 2, 0.1f, tileSize * alto / 2);
		floorVisual.setModelBound(new BoundingBox());
		floorVisual.updateModelBound();

		floor.attachChild(floorVisual);
		floor.generatePhysicsGeometry();
		floor.setLocalTranslation(new Vector3f(tileSize * ancho / 2, -0.1f,
				tileSize * alto / 2));

		final Material playerMaterial = new Material("player material");
		playerMaterial.setDensity(20);
		floor.setMaterial(playerMaterial);

		rootNode.attachChild(floor);

	}

	private void buildInput() {

		input = new ManejadorDeTeclas(player, mazeData, rootNode,
				getPhysicsSpace(),bodyController);

		input.addAction(new InputAction() {
			public void performAction(InputActionEvent evt) {
				bodyController.fadeTo("caminar",0,true);
				
			}
		}, InputHandler.DEVICE_KEYBOARD, KeyInput.KEY_HOME,
				InputHandler.AXIS_NONE, false);

	}

	private void buildMazeWalls() {

		mazeData = new boolean[ancho][alto];

		for (int row = 0; row < ancho; ++row) {
			for (int col = 0; col < alto; ++col) {
				mazeData[row][col] = false;
			}
		}

		// Set RANDOM data
		for (int row = 0; row < ancho; ++row) {
			for (int col = 0; col < alto; ++col) {
				mazeData[row][col] = FastMath.rand.nextBoolean();
			}
		}

		mazeData[1][1] = false;
		mazeData[1][2] = false;
		mazeData[2][1] = false;

		for (int row = 0; row < ancho; ++row) {
			mazeData[row][alto - 1] = true;
			mazeData[row][0] = true;
		}

		for (int col = 0; col < alto; ++col) {
			mazeData[0][col] = true;
			mazeData[ancho - 1][col] = true;
		}

		TextureState ts = display.getRenderer().createTextureState();
		Texture t = TextureManager.loadTexture(getClass().getClassLoader()
				.getResource("data/crate.png"),
				MinificationFilter.NearestNeighborLinearMipMap,
				MagnificationFilter.NearestNeighbor);
		t.setWrap(WrapMode.Repeat);
		ts.setTexture(t);

		for (int row = 0; row < ancho; ++row) {
			for (int col = 0; col < alto; ++col) {
				if (mazeData[row][col]) {

					StaticPhysicsNode node = getPhysicsSpace()
							.createStaticNode();
					node.setName("mazeBox_(" + row + ", " + col + ")");

					Box box = new Box("mazeBox", Vector3f.ZERO.clone(),
							new Vector3f(tileSize, tileSize, tileSize));

					box.setModelBound(new BoundingBox());
					box.updateModelBound();
					box.setRenderState(ts);

					node.attachChild(box);
					node.generatePhysicsGeometry();

					node.setLocalTranslation(row * tileSize, 0, col * tileSize);

					final Material playerMaterial = new Material(
							"player material");
					playerMaterial.setDensity(20);
					node.setMaterial(playerMaterial);

					rootNode.attachChild(node);
					rootNode.updateRenderState();

				}
			}
		}
	}

	private void buildPlayer() {
		
		player = getPhysicsSpace().createDynamicNode();
		player.setName("player");

		URL md5mesh = getClass().getClassLoader().getResource(
				"data/Scene.md5mesh");
		URL animIdle = getClass().getClassLoader().getResource(
				"data/idle.md5anim");
		URL animCaminar = getClass().getClassLoader().getResource(
				"data/caminar.md5anim");
		URL animPlantar = getClass().getClassLoader().getResource(
				"data/plantar.md5anim");
		URL animCall = getClass().getClassLoader().getResource(
				"data/call.md5anim");

		importer = new MD5Importer();
	
		IMD5Animation idle = null;
		IMD5Animation caminar = null;
		IMD5Animation plantar = null;
		IMD5Animation call = null;
		try {
			
			importer.loadMesh(md5mesh, "ModelNode");
			body = importer.getMD5Node();
			
			importer.loadAnim(animIdle, "idle");
			idle = importer.getAnimation();
			
			importer.loadAnim(animCaminar, "caminar");
			caminar = importer.getAnimation();
			
			importer.loadAnim(animPlantar, "plantar");
			plantar = importer.getAnimation();
			
			importer.loadAnim(animCall, "call");
			call = importer.getAnimation();

		} catch (IOException e) {
			System.out.print("no se cargo bien algun dato del jugador, verificar la existencia y la correctitud de la ruta de los archivos .md5mesh y .md4anim");
		}

		
		
		bodyController = new MD5Controller(body);
		bodyController.addAnimation(idle);
		bodyController.addAnimation(plantar);
		bodyController.addAnimation(call);
		bodyController.addAnimation(caminar);

		bodyController.setRepeatType(0);
		bodyController.setActive(true);
		

		body.addController(bodyController);		
		
		Node model = (Node) body; 
		
		Quaternion rot;
		rot = model.getLocalRotation();
		rot.fromAngleAxis((float) +Math.toRadians(90), Vector3f.UNIT_Y);

		model.setLocalScale(.5f);
		
		player.attachChild(model);
		player.setModelBound(new BoundingBox(new Vector3f(0, -8, 0), 7, 5, 7));
		player.generatePhysicsGeometry();
		player.setLocalTranslation(15, 30, 15);
		player.setCenterOfMass(new Vector3f(0, -5f, 0));
		player.setMass(1000);
		final Material playerMaterial = new Material("player material");
		playerMaterial.setDensity(20);
		player.setMaterial(playerMaterial);

		rootNode.attachChild(player);
		rootNode.updateRenderState();

	}


	/**
	 * Setup the Scene.
	 */
	@Override
	protected void simpleInitGame() {
		// a bit more gravity
		getPhysicsSpace().setDirectionalGravity(new Vector3f(0, -50, 0));

		buildFloor();
		buildMazeWalls();
		buildChaseCamera();

		buildPlayer();
		buildEnemy();
		buildInput();
	//	showPhysics = true;

	}

	private void buildEnemy() {
		
		bodyController.fadeTo("plantar", 0, true);

		Enemy enemy = new Enemy(getPhysicsSpace(), mazeData, rootNode);
		
		
		chaseCamera = new ChaseCamera(cam, enemy.getNode(), props);
		chaseCamera.setMaxDistance(300);
		chaseCamera.setMinDistance(190);
		
		Thread thread = new Thread(enemy);
		
		thread.start();
		
	}

	@Override
	protected void simpleUpdate() {
		
		if (bodyController.getActiveAnimation().isCyleComplete()){
		bodyController.fadeTo("idle",0, false);
		}

		
	}

	@Override
	protected void simpleRender() {
		chaseCamera.update(tpf);
	}
}